<?php
namespace Goyello\MVC;

class Controller
{
    const DELETE = 'DELETE';
    const GET = 'GET';
    const ADD = 'POST';
    const UPDATE = 'PUT';

    const ALL = 0;

    const LONG_STRING_LEN = 100;
    const NORMAL_STRING_LEN = 10;
    const SHORT_STRING_LEN = 6;

    const CONTENT_TYPE = 'application/json';

    private $model;
    private $viewData;

    public function __construct()
    {
        $this->model = new Model\Address();
        $this->viewData = Array();
    }

    public function dispatcher($request)
    {
        try
        {
            $id = $this->getIdFromUrl($request['uri']);

            switch ($request['method'])
            {
                case self::DELETE :
                    $view = $this->delete($id);
                    break;
                case self::GET :
                    $view = $this->get($id);
                    break;
                case self::ADD :
                    $view = $this->add($request['data']);
                    break;
                case self::UPDATE :
                    $view = $this->update($id, $request['data']);
                    break;
                default:
                    throw new \Exception('Wybrano nieobsługiwaną metodę HTTP' . $request['method']);
                    break;
            }
            $this->render($view);
        }
        catch(\Exception $e)
        {
            $this->error($e->getMessage());
        }
    }

    private function getIdFromUrl($uri)
    {
        if (!is_string($uri) || strlen($uri) == 0)
        {
            throw new \Exception('Podano nieprawidłowy ciąg znaków jako URI zasobu');
        }

        $parts = explode('/', $uri);

        if (empty($parts[2]))
        {
            return self::ALL;
        }
        if (is_numeric($parts[2]) && $parts[2] > 0)
        {
            return intval($parts[2]);
        }
        throw new \Exception('Podano nieprawidłowy identyfikator adresu');
    }

    public static function fetchPutRequestBody()
    {
        $putdata = fopen("php://input", "r");
        $dataInput = '';
        while ($line = fread($putdata, 1024))
        {
            $dataInput .= $line;
        }
        fclose($putdata);

        return (array)json_decode($dataInput);
    }

    private function delete($id)
    {
        if (self::ALL === $id)
        {
            $this->toDisplay('deleted', $this->model->deleteAll());
        }
        else
        {
            $this->toDisplay('deleted', $this->model->delete($id));
        }
        return 'delete_success';
    }

    private function add($addressToAdd)
    {
        $validAddress = $this->validateAddressObject($addressToAdd);
        $this->toDisplay('address', $this->model->add($validAddress));
        return 'add_success';
    }

    private function update($id, $addressUpdated)
    {
        if (self::ALL === $id)
        {
            throw new \Exception('Nieprawidłowy identyfikatow adresu (' . $id . ')');
        }
        $validAddress = $this->validateAddressObject($addressUpdated);
        $this->toDisplay('status', true);
        $this->toDisplay('result', $this->model->update($id, $validAddress));
        return 'update_success';
    }

    // dla bardziej zaawansowanych struktur mozna $maxLen zamienic na regExp
    private function validateField($address, $field, $maxLen)
    {
        if (is_array($address) && isset($address[$field]))
        {
            $len = strlen($address[$field]);
            if (($len > 0) && ($len <= $maxLen))
            {
                return true;
            }
        }

        throw new \Exception('Podano nieprawidłowe dane. Pole ' .
            $field . ' nie ma prawidłowej długości (min = 1 max = ' .
            $maxLen. ', aktualna = '. $len .')');
    }

    private function validateAddressObject($address)
    {
        $this->validateField($address, 'LABEL', self::LONG_STRING_LEN);
        $this->validateField($address, 'STREET', self::LONG_STRING_LEN);
        $this->validateField($address, 'HOUSENUMBER', self::NORMAL_STRING_LEN);
        $this->validateField($address, 'POSTALCODE', self::SHORT_STRING_LEN);
        $this->validateField($address, 'CITY', self::LONG_STRING_LEN);
        $this->validateField($address, 'COUNTRY', self::NORMAL_STRING_LEN);
        return $address;
    }

    private function get($id)
    {
        if (self::ALL === $id)
        {
            $value = $this->model->getAll();
        }
        else
        {
            $value = $this->model->get($id);
        }
        $this->toDisplay('addresses', $value);
        return 'get_success';
    }

    private function error($msg)
    {
        $this->toDisplay('status', false);
        $this->toDisplay('result', $msg);
        $this->render('error');
    }

    private function render($view)
    {
        $path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'View' .
            DIRECTORY_SEPARATOR . $view . '.php';

        header('Content-type: ' . self::CONTENT_TYPE);

        if (file_exists($path))
        {
            require_once $path;
        }
        else
        {
            die(json_encode(Array(
                'status' => false,
                'reason' => 'brak pliku widoku',
                'file' => $view
            )));
        }
    }

    private function toDisplay($key, $value)
    {
        $this->viewData[$key] = $value;
    }
}

